package cn.ycxy.lbl.search.service.impl;

import cn.ycxy.lbl.common.restful.JsonPage;
import cn.ycxy.lbl.member.service.IUserService;
import cn.ycxy.lbl.pojo.member.vo.UserDetailVO;
import cn.ycxy.lbl.pojo.search.domain.DealDiscussPosts;
import cn.ycxy.lbl.pojo.search.vo.DiscussPostsVO;
import cn.ycxy.lbl.search.repository.DealDiscussPostsRepository;
import cn.ycxy.lbl.search.service.ISearchDealService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

// @DubboService注解,标记的业务逻辑层实现类,其中的所有方法都会注册到Nacos
// 在其他服务启动"订阅"后,就会"发现"当前类中的所有服务,随时可以调用
@DubboService
@Slf4j
@Service
public class SearchDealServiceImpl implements ISearchDealService {

    @Autowired
    private DealDiscussPostsRepository discussPostsRepository;
    @Autowired
    private ElasticsearchRestTemplate restTemplate;

    //这里需要查询每个帖子对应的用户, 需要远程调用用户服务
    @DubboReference(timeout = 3000)
    private IUserService userService;


    @SuppressWarnings("all")
    @Override
    public JsonPage<DiscussPostsVO> search(String keyword, Integer pageNo, Integer pageSize) {
        //查询的字段
        BoolQueryBuilder boolQueryBuilder= QueryBuilders.boolQuery()
                .should(QueryBuilders.matchQuery("content", keyword));
        //构建高亮查询
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                //排序
//                .withSort(SortBuilders.fieldSort("type").order(SortOrder.DESC))
//                .withSort(SortBuilders.fieldSort("score").order(SortOrder.DESC))
                .withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
                .withQuery(boolQueryBuilder)
                //分页
                .withPageable(PageRequest.of(pageNo, pageSize))
                .withHighlightFields(
                        new HighlightBuilder.Field("content")
                )
                //高亮
                .withHighlightBuilder(new HighlightBuilder().preTags("<span>").postTags("</span>"))
                .build();
        //查询
        SearchHits<DealDiscussPosts> search = restTemplate.search(searchQuery, DealDiscussPosts.class);
        //得到查询返回的内容
        List<org.springframework.data.elasticsearch.core.SearchHit<DealDiscussPosts>> searchHits = search.getSearchHits();
        //设置一个最后需要返回的实体类集合
        List<DiscussPostsVO> posts = new ArrayList<>();
        //遍历返回的内容进行处理
        for(SearchHit<DealDiscussPosts> searchHit : searchHits){
            //高亮的内容
            Map<String, List<String>> hfs = searchHit.getHighlightFields();
            //将高亮的内容填充到content中
            String content = hfs.get("content")==null ? searchHit.getContent().getContent():hfs.get("content").get(0);
            searchHit.getContent().setContent("<div>".concat(content).concat("</div>"));
            //放到实体类中
            DealDiscussPosts post = searchHit.getContent();
            UserDetailVO userDetailVO = userService.getUserDetailById(post.getUserId().longValue());
            DiscussPostsVO dealDiscussPostsVO = new DiscussPostsVO();
            BeanUtils.copyProperties(post, dealDiscussPostsVO);
            dealDiscussPostsVO.setUserDetailVO(userDetailVO);
            posts.add(dealDiscussPostsVO);
        }
        // 分页查询调用结束返回Page类型对象,我们要求返回JsonPage类型做统一分页查询的返回
        JsonPage<DiscussPostsVO> jsonPage = new JsonPage<>();
        // 赋值分页信息
        jsonPage.setPage(pageNo);
        jsonPage.setPageSize(pageSize);
        // 赋值分页数据
        jsonPage.setList(posts);
        return jsonPage;
    }

    @Override
    public void saveDiscussPost(DealDiscussPosts discussPost) {
        discussPostsRepository.save(discussPost);
        log.info("deal类型帖子保存到ES服务器中成功! postId为: {}", discussPost.getId());
    }

    @Override
    public void deleteDiscussPostById(long discussPostsId) {
        discussPostsRepository.deleteById(discussPostsId);
        log.info("deal类型帖子从ES服务器中删除成功! postId为: {}", discussPostsId);
    }
}
